package net.muchine.test.ddd.domain.order;

import java.util.HashSet;
import java.util.Set;

import net.muchine.test.ddd.domain.Customer;
import net.muchine.test.ddd.domain.Money;
import net.muchine.test.ddd.exception.OrderLimitExceededException;

public class Order {
	private Long id;
	private String orderId;	
	private Set<OrderLineItem> lineItems = new HashSet<OrderLineItem>();
	private Customer customer;

	private Order() {}
	
	private Order(String orderId, Customer customer) {
		this.orderId = orderId;
		this.customer = customer;
	}
	
	public static Order order(String orderId, Customer customer) {
		return new Order(orderId, customer);
	}

	public Order with(String productName, int quantity) throws OrderLimitExceededException {
		return this.with(new OrderLineItem(productName, quantity));
	}

	private Order with(OrderLineItem lineItem) throws OrderLimitExceededException {
		if (this.isExceedLimit(customer, lineItem)) {
			throw new OrderLimitExceededException();
		}
		
		// if line item has the same product, merge it
		for (OrderLineItem item : lineItems) {
			if (item.isProductEqual(lineItem)) {
				item.merge(lineItem);
				return this;
			}
		}
		
		lineItems.add(lineItem);
		return this;
	}

	private boolean isExceedLimit(Customer customer, OrderLineItem lineItem) {
		return customer.isExceedLimitPrice(this.getPrice().add(lineItem.getPrice()));
	}

	public Long getId() {
		return id;
	}

	public String getOrderId() {
		return orderId;
	}

	public Money getPrice() {
		Money price = new Money(0);
		
		for (OrderLineItem item : lineItems) {
			price = price.add(item.getPrice());
		}
		
		return price;
	}

	public Object getOrderLineItemSize() {
		return lineItems.size();
	}

	public boolean isOrderedBy(Customer customer) {
		return this.customer == customer;
	}

	@Override
	public int hashCode() {
		return this.orderId.hashCode();
	}

	@Override
	public boolean equals(Object object) {
		if (object == this) return true;
		
		if (!(object instanceof Order)) return false;
		
		final Order order = (Order) object;
		return this.equals(this.orderId.equals(order.getOrderId()));
	}
}
